
#include <BFont>
#include <BTableItem>
#include <BListItem>

#include "CutoffOperation.h"
#include "LayerDragger.h"
#include "PaintOperation.h"
#include "EraseOperation.h"
#include "ImageLayer.h"
#include "MainWindow.h"

MainWindow::MainWindow()
{
	_canvasMenu = new BMenu("Canvas");
	{
		BLabel* formatLabel = new BLabel("Format : rgba");

		BGridLayout* gridLayout = new BGridLayout();
		{
			BLabel* widthLabel = new BLabel("Width");
			_canvasWidthSpinBox = new BSpinBox();
			_canvasWidthSpinBox->setSuffix("px");

			BLabel* heightLabel = new BLabel("Height");
			_canvasHeightSpinBox = new BSpinBox();
			_canvasHeightSpinBox->setSuffix("px");

			gridLayout->setWidget(1, 0, widthLabel);
			gridLayout->setWidget(1, 1, _canvasWidthSpinBox);
			gridLayout->setWidget(2, 0, heightLabel);
			gridLayout->setWidget(2, 1, _canvasHeightSpinBox);
		}

		BHBoxLayout* backgroundLayout = new BHBoxLayout();
		{
			BLabel* backgroundLabel = new BLabel("background");
			_canvasImageButton = new BButton();
			backgroundLayout->addWidget(backgroundLabel);
			backgroundLayout->addWidget(_canvasImageButton);
		}
		BVBoxLayout* vlayout = new BVBoxLayout(_canvasMenu);
		vlayout->addWidget(formatLabel);
		vlayout->addLayout(gridLayout);
		vlayout->addLayout(backgroundLayout);
	}

	_modifyMenu = new BMenu("Modify");
	{
		_modifyMenu->addAction("replace");
	}

	BHBoxLayout* toolsLayout = new BHBoxLayout();
	toolsLayout->setSpacing(2);
	{
		_openButton = new BButton("Open");
		_openButton->setForm(Form_IconAlone);

		_saveButton = new BButton("Save");
		_saveButton->setForm(Form_IconAlone);

		_resetButton = new BButton("Reset");
		_resetButton->setForm(Form_IconAlone);

		_insertButton = new BButton("Insert");

		_canvasButton = new BButton();
		_canvasButton->setMenu(_canvasMenu);

		_modifyButton = new BButton("modify");
		_modifyButton->setMenu(_modifyMenu);

		BLabel* zoomLabel = new BLabel("Zoom");
		_zoomSlider = new BSlider(1, 1000);
		_resetZoomButton = new BButton("reset-zoom");
		_resetZoomButton->setForm(Form_IconAlone);

		_eventEnabledCheckBox = new BCheckBox("event-enabled");

		toolsLayout->addWidget(_openButton);
		toolsLayout->addWidget(_saveButton);
		toolsLayout->addWidget(_resetButton);
		toolsLayout->addWidget(_insertButton);
		toolsLayout->addWidget(_canvasButton);
		toolsLayout->addWidget(_modifyButton);
		toolsLayout->addSpacer(3);
		toolsLayout->addWidget(zoomLabel);
		toolsLayout->addWidget(_zoomSlider);
		toolsLayout->addWidget(_resetZoomButton);
		toolsLayout->addSpacer(3);
		toolsLayout->addWidget(_eventEnabledCheckBox);
		toolsLayout->addSpring();
	}

	BVBoxLayout* leftLayout = new BVBoxLayout();
	leftLayout->setWidthPolicy(Policy_Preferred);
	{
		BButton* dragButton = new BButton("drag");
		dragButton->setForm(Form_IconAlone);
		dragButton->setAsset(new LayerDragger());

		BButton* cutoffButton = new BButton("cutoff");
		cutoffButton->setForm(Form_IconAlone);
		cutoffButton->setTips("Cutoff to new layer");
		cutoffButton->setAsset(new CutoffOperation());

		BButton* taosuoButton = new BButton("taosuo");
		taosuoButton->setForm(Form_IconAlone);

		BButton* paintButton = new BButton("paint");
		paintButton->setForm(Form_IconAlone);
		paintButton->setAsset(new PaintOperation());

		BButton* eraseButton = new BButton("erase");
		eraseButton->setForm(Form_IconAlone);
		eraseButton->setAsset(new EraseOperation());

		leftLayout->addWidget(dragButton);
		leftLayout->addWidget(cutoffButton);
		leftLayout->addWidget(taosuoButton);
		leftLayout->addWidget(paintButton);
		leftLayout->addWidget(eraseButton);
		leftLayout->addSpring();

		_buttonGroup = new BButtonGroup();
		_buttonGroup->addButton(cutoffButton);
		_buttonGroup->addButton(dragButton);
		_buttonGroup->addButton(taosuoButton);
		_buttonGroup->addButton(paintButton);
		_buttonGroup->addButton(eraseButton);
	}

	BVBoxLayout* centerLayout = new BVBoxLayout();
	{
		_pixmapArea = new PixmapArea();

		BHBoxLayout* statusLayout = new BHBoxLayout();
		{
			BLabel* layerLabel = new BLabel("layer");
			_layerXSpinBox = new BSpinBox();
			_layerYSpinBox = new BSpinBox();

			BLabel* globalLabel = new BLabel("global");
			_globalXSpinBox = new BSpinBox();
			_globalYSpinBox = new BSpinBox();

			statusLayout->addSpring(100);
			statusLayout->addWidget(layerLabel);
			statusLayout->addWidget(_layerXSpinBox);
			statusLayout->addWidget(_layerYSpinBox);
			statusLayout->addSpacer(10);
			statusLayout->addWidget(globalLabel);
			statusLayout->addWidget(_globalXSpinBox);
			statusLayout->addWidget(_globalYSpinBox);
		}
		centerLayout->addWidget(_pixmapArea);
		centerLayout->addLayout(statusLayout, 0);
	}

	_rightLayout = new BVBoxLayout();
	_rightLayout->setSplitable(true);
	_rightLayout->setSpacing(6);
	{
		_imageLayerPanel = new LayerPanel();

		_layersBoard = new LayersBoard();
		_layersBoard->setColumnCount(3);
		_layersBoard->setColumnPolicy(Policy_Preferred);
		_layersBoard->setStyleSheet("item-color-hovered:empty");
		_layersBoard->setHorizontalScrollPolicy(ScrollPolicy_Never);
		_layersBoard->setSelectMode(Select_Multiple | Select_Rows);
		_layersBoard->setHeightPolicy(Policy_Dynamic);
		{
			_arrowUpButton = new BButton(Graph_Arrow_Up_Fill);
			_arrowUpButton->setForm(Form_IconAlone);

			_arrowDownButton = new BButton(Graph_Arrow_Down_Fill);
			_arrowDownButton->setForm(Form_IconAlone);

			_layerInsertButton = new BButton("insert");
			_layerInsertButton->setName("insert");
			_layerInsertButton->setForm(Form_IconAlone);
			_layerInsertButton->setTips("insert layer to the list.");

			_layerRemoveButton = new BButton("remove");
			_layerRemoveButton->setName("remove");
			_layerRemoveButton->setForm(Form_IconAlone);
			_layerRemoveButton->setTips("remove layer from the list.");

			_layerExportButton = new BButton("export");
			_layerExportButton->setName("export");
			_layerExportButton->setForm(Form_IconAlone);
			_layerExportButton->setTips("export layer image to file.");

			_imageSizeComboBox = new BComboBox();
			_imageSizeComboBox->addItem("20", 20);
			_imageSizeComboBox->addItem("40", 40);
			_imageSizeComboBox->addItem("80", 80);
			_imageSizeComboBox->setCurrentIndex(0);

			BHBoxLayout* buttonLayout = new BHBoxLayout();
			buttonLayout->addWidget(_arrowUpButton, 0);
			buttonLayout->addWidget(_arrowDownButton, 0);
			buttonLayout->addWidget(_layerInsertButton, 0);
			buttonLayout->addWidget(_layerRemoveButton, 0);
			buttonLayout->addWidget(_layerExportButton, 0);
			buttonLayout->addSpring();
			buttonLayout->addWidget(_imageSizeComboBox);
			_layersBoard->setLayout(buttonLayout, Part_Top);
		}

		_rightLayout->addWidget(_imageLayerPanel, 0);
		_rightLayout->addWidget(_layersBoard);
		_rightLayout->setWidthPolicy(Policy_Preferred | Policy_Dynamic);
	}

	BHBoxLayout* splitLayout = new BHBoxLayout();
	splitLayout->setSplitable(true);
	splitLayout->setSpacing(6);
	splitLayout->addLayout(leftLayout);
	splitLayout->addLayout(centerLayout, 10);
	splitLayout->addLayout(_rightLayout);

	BVBoxLayout* layout = new BVBoxLayout(this);
	layout->addLayout(toolsLayout);
	layout->addLayout(splitLayout, 1000);

	connect(_openButton, Signal_Clicked, &MainWindow::slotOpenButtonClicked);
	connect(_saveButton, Signal_Clicked, &MainWindow::slotSaveButtonClicked);
	connect(_resetButton, Signal_Clicked, &MainWindow::slotResetButtonClicked);
	connect(_insertButton, Signal_Clicked, &MainWindow::slotInsertButtonClicked);
	connect(_canvasWidthSpinBox, Signal_EditFinished, &MainWindow::slotCanvasResized);
	connect(_canvasHeightSpinBox, Signal_EditFinished, &MainWindow::slotCanvasResized);
	connect(_canvasImageButton, Signal_Clicked, &MainWindow::slotChooseCanvasImage);
	connect(_modifyMenu, Signal_Triggered, &MainWindow::slotModifyMenuTrigger);
	connect(_zoomSlider, Signal_ValueChanged, &MainWindow::slotZoomValueChanged);
	connect(_resetZoomButton, Signal_Clicked, &MainWindow::slotResetZoomButtonClicked);
	connect(_eventEnabledCheckBox, Signal_Checked, &MainWindow::slotEventEnabledChecked);
	connect(_buttonGroup, Signal_Checked, &MainWindow::slotButtonGroupChecked);

	connect(_arrowUpButton, Signal_Clicked, &MainWindow::slotArrowUpClicked);
	connect(_arrowDownButton, Signal_Clicked, &MainWindow::slotArrowDownClicked);
	connect(_layerInsertButton, Signal_Clicked, &MainWindow::slotLayerInsertClicked);
	connect(_layerRemoveButton, Signal_Clicked, &MainWindow::slotLayerRemoveClicked);
	connect(_layerExportButton, Signal_Clicked, &MainWindow::slotLayerExportClicked);
	connect(_imageSizeComboBox, Signal_ValueChanged, &MainWindow::slotImageSizeChanged);
	connect(_layersBoard, Signal_ItemSelected, &MainWindow::slotLayerItemSelected);

	connect(_pixmapArea, "zoom-changed", &MainWindow::slotPixmapZoomChanged);
	connect(_pixmapArea, "widget-selected", &MainWindow::slotWidgetSelected);
	connect(_pixmapArea, "widget-unselected", &MainWindow::slotWidgetUnselected);
	connect(_pixmapArea, "operation-escape", &MainWindow::slotOperationEscape);
	connect("layer-arranged", &MainWindow::slotWidgetOrderAdjusted);
	connect("insert-layer", &MainWindow::slotInsertImageLayer);
	connect("remove-layer", &MainWindow::slotRemoveImageLayer);
	connect("layer-point", &MainWindow::slotLayerPoint);
	connect("global-point", &MainWindow::slotGlobalPoint);
	connect("operation", &MainWindow::slotOperation);
	connect("selection", &MainWindow::slotSelection);

	_pixmapArea->pixmap()->setSize(800, 800);
	_canvasWidthSpinBox->setValue(800);
	_canvasHeightSpinBox->setValue(800);
	_zoomSlider->setValue(100);
}
MainWindow::~MainWindow()
{

}

bool MainWindow::openImage(const BString& fileName)
{
	BImage* image = ReadFile<BImage>(fileName);
	if (!image)
		return false;

	BPixmap* pixmap = _pixmapArea->pixmap();
	pixmap->setSize(image->size());
	_canvasWidthSpinBox->setValue(image->width());
	_canvasHeightSpinBox->setValue(image->height());
	_zoomSlider->setValue(100);

	ImageLayer* layer = new ImageLayer();
	layer->setName(fileName.name());
	layer->setImage(image);
	layer->setSize(image->size());
	emit("insert-layer", layer);

	return true;
}

void MainWindow::slotOpenButtonClicked(BObject* object, const BValue& value)
{
	BString fileName = BFileDialog::OpenFile(this, "Open Image File");
	openImage(fileName);
}
void MainWindow::slotSaveButtonClicked(BObject* object, const BValue& value)
{
	BString fileName = BFileDialog::SaveFile(this, "Save Image File");
	if (fileName.size())
	{
		BImage* image = _pixmapArea->image();
		bool ret = WriteFile<BImage>(fileName, image);
	}
}
void MainWindow::slotResetButtonClicked(BObject* object, const BValue& value)
{
	_pixmapArea->clearSelection();
	_pixmapArea->pixmap()->clearWidgets();
	_layersBoard->clearItems();
}
void MainWindow::slotInsertButtonClicked(BObject* object, const BValue& value)
{
	BString fileName = BFileDialog::OpenFile(this, "Open Image File");
	if (BImage* image = ReadFile<BImage>(fileName))
	{
		image->setFileName(fileName);
		ImageLayer* layer = new ImageLayer();
		layer->setName(fileName.name());
		layer->setImage(image);
		emit("insert-layer", layer);
	}
}
void MainWindow::slotCanvasResized(BObject* object, const BValue& value)
{
	int width = _canvasWidthSpinBox->value();
	int height = _canvasHeightSpinBox->value();
	_pixmapArea->pixmap()->setSize(width, height);
}
void MainWindow::slotChooseCanvasImage(BObject* object, const BValue& value)
{
	BButton* button = dynamic_cast<BButton*>(object);
	const BString& fileName = BFileDialog::OpenFile("Choose canvas image", "", "*.png;*.jpg;*.tiff");
	if (fileName.size())
	{
		BImage* image = ReadFile<BImage>(fileName);
		button->setImage(image);
		_pixmapArea->setAreaImage(image);
	}
}
void MainWindow::slotModifyMenuTrigger(BObject* object, const BValue& value)
{
	if (BAction* action = value)
	{
		if (action->text() == "replace")
		{
			if (_replaceDialog.empty())
			{
				_replaceDialog = new ReplaceDialog();
				_replaceDialog->setSizePolicy(Policy_Preferred | Policy_Expanding, Policy_Preferred);
				connect(_replaceDialog, Signal_Close, &MainWindow::slotReplaceDialogClosed);
			}
			_replaceDialog->setParent(this);
			_replaceDialog->popup();
		}
	}
}
void MainWindow::slotZoomValueChanged(BObject* object, const BValue& value)
{
	int zoom = value;
	_pixmapArea->setZoom(zoom);
	_resetZoomButton->setEnabled(zoom != 100);
}
void MainWindow::slotResetZoomButtonClicked()
{
	_zoomSlider->setValue(100);
}
void MainWindow::slotEventEnabledChecked()
{
	if (_eventEnabledCheckBox->checked())
		_pixmapArea->enableEvent();
	else
		_pixmapArea->disableEvent();
}
void MainWindow::slotButtonGroupChecked(BObject* object, const BValue& value)
{
	if (BButton* button = value)
	{
		if (button->checked())
		{
			Operation* operation = button->asset();
			emit("operation", operation);
		}
		else
		{
			emit("operation");
		}
	}
}
void MainWindow::slotOperationEscape(BObject* object, const BValue& value)
{
	if (BButton* button = _buttonGroup->buttonOfAsset(value))
	{
		button->setChecked(false);
	}
}
void MainWindow::slotOperation(BObject* object, const BValue& value)
{
	Operation* operation = value;
	_pixmapArea->setOperation(operation);
}
void MainWindow::slotSelection(BObject* object, const BValue& value)
{
	BPolygon& polygon = value;
	//_polygons.append(polygon);
}

void MainWindow::slotArrowUpClicked()
{
	int row = _layersBoard->selectedItem()->row();
	BWidget* widget = _layersBoard->rowAsset(row);
	BArray<BTableItemHolder> items;
	for (int c = 0; c < _layersBoard->columnCount(); c++)
	{
		items.append(_layersBoard->item(row, c));
	}
	_layersBoard->removeRows(row);
	_layersBoard->insertRows(row - 1);
	_layersBoard->setRowAsset(row - 1, widget);
	for (int c = 0; c < _layersBoard->columnCount(); c++)
	{
		_layersBoard->setItem(row - 1, c, items[c]);
	}
	_layersBoard->setRowLabel(row - 1, row - 1);
	_layersBoard->setRowLabel(row, row);
	emit("layer-arranged", row - 1);
}
void MainWindow::slotArrowDownClicked()
{
	int row = _layersBoard->selectedItem()->row();
	BArray<BTableItemHolder> items;
	for (int c = 0; c < _layersBoard->columnCount(); c++)
	{
		items.append(_layersBoard->item(row, c));
	}
	_layersBoard->removeRows(row);
	_layersBoard->insertRows(row + 1);
	for (int c = 0; c < _layersBoard->columnCount(); c++)
	{
		_layersBoard->setItem(row + 1, c, items[c]);
	}
	_layersBoard->setRowLabel(row + 1, row + 1);
	_layersBoard->setRowLabel(row, row);
	emit("layer-arranged", row);
}
void MainWindow::slotLayerInsertClicked()
{
	if (_createLayerDialog.empty())
	{
		_createLayerDialog = new CreateLayerDialog(this);
	}
	BStringList namelst;
	for (int i = 0; i < _layersBoard->rowCount(); i++)
	{
		ImageLayer* layer = _layersBoard->rowAsset(i);
		namelst.append(layer->name());
	}
	_createLayerDialog->setNameList(namelst);
	if (_createLayerDialog->execute())
	{
		emit("insert-layer", _createLayerDialog->asset());
		_createLayerDialog->setAsset(BValue());
	}
}
void MainWindow::slotLayerRemoveClicked()
{
	while (BTableItem* item = _layersBoard->selectedItem())
	{
		ImageLayer* layer = _layersBoard->rowAsset(item->row());
		emit("remove-layer", layer);
	}
}
void MainWindow::slotLayerExportClicked()
{
	BWidget* widget = _pixmapArea->selectedWidgets().first();
	if (ImageLayer* layer = dynamic_cast<ImageLayer*>(widget))
	{
		BString fileName = BFileDialog::SaveFile(this, "Save Image File");
		if (fileName.size())
		{
			BImage* image = layer->image();
			bool ret = WriteFile<BImage>(fileName, image);
		}
	}
}
void MainWindow::slotImageSizeChanged(BObject* object, const BValue& value)
{
	int imageSize = _imageSizeComboBox->value();
	for (int r = 0; r < _layersBoard->rowCount(); r++)
	{
		_layersBoard->item(r, 1)->setIconSize(imageSize);
	}
}
void MainWindow::slotLayerItemSelected(BObject* object, const BValue& value)
{
	BTableItem* item = value;
	if (item->isSelected())
	{
		BWidget* widget = _layersBoard->rowAsset(item->row());
		_pixmapArea->select(widget);
	}
	else
	{
		BWidget* widget = _layersBoard->rowAsset(item->row());
		_pixmapArea->unselect(widget);
	}
}

void MainWindow::slotEyeButtonChecked(BObject* object, const BValue& value)
{
	for (int r = 0; r < _layersBoard->rowCount(); r++)
	{
		BTableItem* item = _layersBoard->item(r, 0);
		if (item->widget() == object)
		{
			BWidget* widget = _layersBoard->rowAsset(r);
			widget->setVisible(value);
		}
	}
}
void MainWindow::slotWidgetFrame(BObject* object, const BValue& value)
{
	for (int r = 0; r < _layersBoard->rowCount(); r++)
	{
		BWidget* widget = _layersBoard->rowAsset(r);
		if (widget == object)
		{
			BTableItem* imageItem = _layersBoard->item(r, 1);
			BImage* image = imageItem->image();
			widget->capture(image);
			image->reverse(Orientation_Vertical);
			_layersBoard->fresh();
		}
	}
}
void MainWindow::slotReplaceDialogClosed(BObject* object, const BValue& value)
{
	_replaceDialog->setParent(0);
}

void MainWindow::slotPixmapZoomChanged(BObject* object, const BValue& value)
{
	int zoom = value;
	_zoomSlider->setValue(zoom);
}
void MainWindow::slotWidgetSelected(BObject* object, const BValue& value)
{
	ImageLayer* layer = value;
	int row = _layersBoard->rowOfAsset(value);
	_layersBoard->setRowSelected(row, true);
	_imageLayerPanel->setAsset(layer);
}
void MainWindow::slotWidgetUnselected(BObject* object, const BValue& value)
{
	ImageLayer* layer = value;
	int row = _layersBoard->rowOfAsset(value);
	_layersBoard->setRowSelected(row, false);

	BWidget* lastWidget = _pixmapArea->selectedWidgets().last();
	_imageLayerPanel->setAsset(lastWidget);
}
void MainWindow::slotWidgetOrderAdjusted(BObject* object, const BValue& value)
{
	BPixmap* pixmap = _pixmapArea->pixmap();
	pixmap->clearWidgets();
	for (int r = 0; r < _layersBoard->rowCount(); r++)
	{
		BWidget* widget = _layersBoard->rowAsset(r);
		pixmap->addWidget(widget);
	}
}
void MainWindow::slotInsertImageLayer(BObject* object, const BValue& value)
{
	ImageLayer* layer = value;
	if (BImage* image = value)
	{
		layer = new ImageLayer();
		layer->setName(image->name());
		layer->setImage(image);
	}
	if(layer)
	{
		BPixmap* pixmap = _pixmapArea->pixmap();
		if (layer->size() != pixmap->size())
		{
			BRect view = _pixmapArea->area() & _pixmapArea->centerRect();
			view = _pixmapArea->mapToPixmap(view);
			BRect rect = view.align(Align_Center, layer->size());
			layer->setRect(rect);
		}

		pixmap->addWidget(layer);

		BButton* button = new BButton();
		button->setName("eye");
		button->setForm(Form_IconAlone);
		button->setCheckable(true);
		button->setChecked(true);
		connect(button, Signal_Checked, &MainWindow::slotEyeButtonChecked);

		int row = _layersBoard->addRows();
		int imageSize = _imageSizeComboBox->value();
		_layersBoard->setRowPolicy(row, Policy_Preferred);
		_layersBoard->setRowLabel(row, row);
		_layersBoard->setRowAsset(row, layer);
		_layersBoard->setItem(row, 0, button)->setAlign(Align_Center);
		BImage* image = new BImage(Format_RGBA);
		_layersBoard->setItem(row, 1, image)->setIconSize(imageSize);
		_layersBoard->setItem(row, 2, layer->name());
		connect(layer, Signal_Frame, &MainWindow::slotWidgetFrame);

		_pixmapArea->clearSelection();
		_pixmapArea->select(layer);
	}
}
void MainWindow::slotRemoveImageLayer(BObject* object, const BValue& value)
{
	ImageLayer* layer = value;
	if (BImage* image = value)
	{
		layer = _pixmapArea->findLayer(image);
	}
	if(layer)
	{
		_pixmapArea->unselect(layer);
		BPixmap* pixmap = _pixmapArea->pixmap();
		pixmap->removeWidget(layer);
		int row = _layersBoard->rowOfAsset(layer);
		_layersBoard->removeRows(row);
	}
}
void MainWindow::slotLayerPoint(BObject* object, const BValue& value)
{
	const BPoint& point = value;
	_layerXSpinBox->setValue(point.x());
	_layerYSpinBox->setValue(point.y());
}
void MainWindow::slotGlobalPoint(BObject* object, const BValue& value)
{
	const BPoint& point = value;
	_globalXSpinBox->setValue(point.x());
	_globalYSpinBox->setValue(point.y());
}

void MainWindow::styleEvent(const BEvent& event)
{
	const BStyle* style = this->realStyle();
	if (style)
	{
		for (int i = 0; i < _buttonGroup->buttonCount(); i++)
		{
			BButton* button = _buttonGroup->button(i);
			BIcon* icon = style->icon(button->text());
			button->setIcon(icon);
		}
		_arrowUpButton->setIconSize(style->font()->size() / 2);
		_arrowDownButton->setIconSize(style->font()->size() / 2);
	}
}
void MainWindow::updateEvent(const BEvent& event)
{

}
